﻿using System;
using System.Collections.Generic;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace pdftron.PDF.Tools.Controls.ViewModels.Common
{
    public class RelayCommand : ICommand 
    {
        // Event that fires when the enabled/disabled state of the cmd changes
        public event EventHandler CanExecuteChanged;

        // Delegate for method to call when the cmd needs to be executed        
        private readonly Action<object> _targetExecuteMethod;

        // Delegate for method that determines if cmd is enabled/disabled        
        private readonly Predicate<object> _targetCanExecuteMethod;

        public bool CanExecute(object parameter)
        {
            return _targetCanExecuteMethod == null || _targetCanExecuteMethod(parameter);
        }

        public void Execute(object parameter)
        {
            // Call the delegate if it's not null
            if (_targetExecuteMethod != null) _targetExecuteMethod(parameter);
        }

        public RelayCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod = null)
        {
            _targetExecuteMethod = executeMethod;
            _targetCanExecuteMethod = canExecuteMethod;
        }

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty);
        }

    }



    public static class ChildScrollViewerScrollChangedCommand
    {
        public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(ChildScrollViewerScrollChangedCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as ListViewBase;
            if (control != null)
            {
                if (_ListViewBaseChildren.ContainsKey(control))
                {
                    return;
                }
                if (!AttachScrollEvent(control))
                    control.SizeChanged += (s, eargs) =>
                    {
                        AttachScrollEvent(control);
                    };
            }
        }

        private static bool AttachScrollEvent(ListViewBase control)
        {
            ScrollViewer childScroller = pdftron.PDF.Tools.UtilityFunctions.FindVisualChild<ScrollViewer>(control);
            if (childScroller != null)
            {
                _ScrollViewerParents[childScroller] = control;
                _ListViewBaseChildren[control] = childScroller;
                childScroller.ViewChanged += childScroller_ViewChanged;
                return true;
            }
            return false;
        }

        static void childScroller_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
        {
            var scroller = sender as ScrollViewer;
            var command = GetCommand(_ScrollViewerParents[scroller]);

            if (command != null && command.CanExecute(e))
                command.Execute(sender);
        }
        private static Dictionary<ScrollViewer, ListViewBase> _ScrollViewerParents = new Dictionary<ScrollViewer, ListViewBase>();
        private static Dictionary<ListViewBase, ScrollViewer> _ListViewBaseChildren = new Dictionary<ListViewBase, ScrollViewer>();
    }

    public static class ChildScrollViewerSizeChanged
    {
        public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(ChildScrollViewerSizeChanged), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as ListViewBase;
            if (control != null)
            {
                if (_ListViewBaseChildren.ContainsKey(control))
                {
                    return;
                }
                AttachSizeEvent(control);
                control.SizeChanged += (s, eargs) =>
                {
                    if (!_ListViewBaseChildren.ContainsKey(control))
                    {
                        AttachSizeEvent(control);
                    }
                };
                control.Unloaded += (s, eargs) =>
                {
                    if (_ListViewBaseChildren.ContainsKey(control))
                    {
                        _ScrollViewerParents.Remove(_ListViewBaseChildren[control]);
                        _ListViewBaseChildren.Remove(control);
                    }
                };
            }
        }



        private static bool AttachSizeEvent(ListViewBase control)
        {
            ScrollViewer scrollViewer = UtilityFunctions.FindVisualChild<ScrollViewer>(control);
            if (scrollViewer != null)
            {
                _ScrollViewerParents[scrollViewer] = control;
                _ListViewBaseChildren[control] = scrollViewer;
                scrollViewer.SizeChanged += panel_SizeChanged;

                var command = GetCommand(_ScrollViewerParents[scrollViewer]);
                if (command != null && command.CanExecute(scrollViewer))
                    command.Execute(scrollViewer);

                return true;
            }
            return false;
        }

        static void panel_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ScrollViewer scrollViewer = sender as ScrollViewer;
            ListViewBase parent = _ScrollViewerParents[scrollViewer];
            var command = GetCommand(_ScrollViewerParents[scrollViewer]);
            if (command != null && command.CanExecute(sender))
                command.Execute(sender);
        }

        private static Dictionary<ScrollViewer, ListViewBase> _ScrollViewerParents = new Dictionary<ScrollViewer, ListViewBase>();
        private static Dictionary<ListViewBase, ScrollViewer> _ListViewBaseChildren = new Dictionary<ListViewBase, ScrollViewer>();
    }

    public static class SelectionChangedCommand
    {
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(SelectionChangedCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            ListViewBase control = d as ListViewBase;
            if (control != null)
                control.SelectionChanged += control_SelectionChanged;
        }

        static void control_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListViewBase control = sender as ListViewBase;
            var command = GetCommand(control);

            if (command != null && command.CanExecute(sender))
            {
                command.Execute(sender);
            }
        }
    }

    public static class ItemClickCommand
    {
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(ItemClickCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            ListViewBase control = d as ListViewBase;
            if (control != null)
                control.ItemClick += control_ItemClick;
        }

        static void control_ItemClick(object sender, ItemClickEventArgs e)
        {
            ListViewBase control = sender as ListViewBase;
            var command = GetCommand(control);

            if (command != null && command.CanExecute(e))
            {
                command.Execute(e);
            }
        }
    }


    public static class LoadedCommand
    {
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(LoadedCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as FrameworkElement;
            if (control != null)
                control.Loaded += control_Loaded;
        }

        static void control_Loaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement control = sender as FrameworkElement;
            var command = GetCommand(control);

            if (command != null && command.CanExecute(sender))
            {
                command.Execute(sender);
            }
        }
    }

    public static class SizechangedCommand
    {
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(SizechangedCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as FrameworkElement;
            if (control != null)
                control.SizeChanged += control_SizeChanged;
        }

        static void control_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            FrameworkElement control = sender as FrameworkElement;
            var command = GetCommand(control);

            if (command != null && command.CanExecute(sender))
            {
                command.Execute(e);
            }
        }
    }

    public static class SizeChangedCommand
    {
        public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(SizeChangedCommand), new PropertyMetadata(null, OnCommandPropertyChanged));

        public static void SetCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(CommandProperty);
        }

        private static void OnCommandPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var control = d as FrameworkElement;
            if (control != null)
                control.SizeChanged += control_SizeChanged;
        }

        static void control_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            FrameworkElement control = sender as FrameworkElement;
            var command = GetCommand(control);

            if (command != null && command.CanExecute(e))
            {
                command.Execute(e);
            }
        }
    }
}
